#ifndef LGE2D_LAN_CONNECTION_H_
#define LGE2D_LAN_CONNECTION_H_

#include "packet.hpp"
#include "lan_cfg.hpp"

#include <vector>

namespace lge2d
{
namespace lan
{
// класс для хранения и обработки подключения
/**
	При подключении к серверу клиентское соединение проходит несколько стадий:
	1. проверка правильности ip адреса сервера
	2. инициируется установление соединения (Connecting)
	3. после начала попытки соединения клиент обязан получить тестовый пакет
	 от сервера и отправить аналогичный серверу, иначе соединение будет
	 разорвано. Если такой пакет не отправит сервер, клиент разорвет соединение
	 по таймауту. (Validating)
	4. соединение уситановлено и переходит в состояние Connected.
 */
class Connection
{
public:

	/// состояния сокета
	enum State
	{
		Connecting,		///< Идет подключение
		Validating,		///< Соединение проходит валидацию
		Connected,		///< Соединение установлено
		Disconnected	///< Соединение разорвано
	};

	/// Ошибки, возникающие при работе соединения
	enum ErrorCode
	{
		NoError,
		Error,
		InvalidHostAddress,
		AlreadyConnected,
		ConnectingTimeOut,
		ConnectionLost,
		NotValidated
	};

	struct Statictics
	{
		unsigned totalPacktesSent;
		unsigned totalPacktesReceived;

		unsigned totalBytesSent;
		unsigned totalBytesReceived;

		Statictics():
			totalPacktesSent(0),
			totalPacktesReceived(0),
			totalBytesSent(0),
			totalBytesReceived(0)
		{}
	};

public:
	// Констуруктор по умолчанию. Используется на стороне клиента
	Connection();
	/// конструктор для сервера
	Connection(sf::SocketTCP& socket, float timeOut = CLIENT_CONNECTIONG_TIMEOUT);
	/** Внимание. Деструктор не закрывает соединение.
	 * Должно быть остановлено с помощью функции Disconnect().
	 */
	virtual ~Connection();

	/** возвращает false в случае, когда соединение находится в состоянии
	 * Disconnected.
	 */
	bool Update(float dt);

	State GetState() const;
	ErrorCode GetLastError() const;
	const Statictics& GetStatistics() const;

	/** Отправка пакета. Пакет помещается в очередь отправки.
	 * За один раз может быть отправлено не более SOCKET_MAX_PACKETS_COUNT
	 * пакетов.
	 */
	void Send(Packet& packet);
	// Получить колличество пакетов в очереди отправки.
	size_t GetSendCount() const;

	// Получить число полученных пакетов
	size_t GetReceivedCount() const;
	// полученный пакет по индексу
	const Packet& Get(size_t idx) const;
	// Очистить очередь полученных пакетов после использования
	void ClearReceived();

	// подключение к серверу
	ErrorCode Connect(const std::string& host,
			unsigned short port = DEFAULT_SERVER_PORT,
			float timeOut = CLIENT_CONNECTIONG_TIMEOUT);

	// разрыв соединения
	void Disconnect();

private:
	State m_state;
	ErrorCode m_last_error;
	bool  m_server_socket;
	//
	std::vector<Packet> m_input_packets; // полученные пакеты
	std::vector<Packet> m_output_packets; // пакеты для отправки
	//
	sf::SocketTCP m_socket;
	Statictics m_statistic;
	//
	float m_connecting_timeout;
};

} /* namespace lan */
} /* namespace lge2d */

#endif /* LGE2D_LAN_CONNECTION_H_ */
